package com.weilele.mvvm.utils.glide

import android.app.Activity
import android.content.Context
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.widget.ImageView
import androidx.annotation.WorkerThread
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.palette.graphics.Palette
import androidx.palette.graphics.get
import com.bumptech.glide.Glide
import com.bumptech.glide.RequestManager
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.load.resource.bitmap.CircleCrop
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.Target
import com.weilele.mvvm.utils.activity.dip
import com.weilele.mvvm.utils.coroutine.awaitAny
import com.weilele.mvvm.utils.printStackTrace
import top.zibin.luban.Luban
import java.io.File
import kotlin.coroutines.resume


data class AwaitResult<T>(
    var result: T?,
    var throwable: Throwable?
)

suspend fun Context.downloadDrawableByGlide(url: String?): AwaitResult<Drawable> {
    return downloadDrawableByGlide(url, Glide.with(this))
}

suspend fun Fragment.downloadDrawableByGlide(url: String?): AwaitResult<Drawable> {
    return downloadDrawableByGlide(url, Glide.with(this))
}

suspend fun downloadDrawableByGlide(url: String?, glide: RequestManager): AwaitResult<Drawable> {
    url ?: return AwaitResult(null, IllegalStateException("url is null"))
    return awaitAny {
        val request = glide
            .load(url)
            .addListener(object : RequestListener<Drawable> {
                override fun onLoadFailed(
                    e: GlideException?,
                    model: Any?,
                    target: Target<Drawable>?,
                    isFirstResource: Boolean
                ): Boolean {
                    it.resume(AwaitResult<Drawable>(null, e))
                    return true
                }

                override fun onResourceReady(
                    resource: Drawable?,
                    model: Any?,
                    target: Target<Drawable>?,
                    dataSource: DataSource?,
                    isFirstResource: Boolean
                ): Boolean {
                    it.resume(AwaitResult(resource, null))
                    return true
                }
            })
            .submit()
        it.invokeOnCancellation { t ->
            request.cancel(true)
            it.resume(AwaitResult<Drawable>(null, t))
        }
    }
}

suspend fun Context.downloadFileByGlide(url: String?): AwaitResult<File> {
    return downloadFileByGlide(url, Glide.with(this))
}

suspend fun Fragment.downloadFileByGlide(url: String?): AwaitResult<File> {
    return downloadFileByGlide(url, Glide.with(this))
}

suspend fun downloadFileByGlide(url: String?, glide: RequestManager): AwaitResult<File> {
    url ?: return AwaitResult(null, IllegalStateException("url is null"))
    return awaitAny {
        val request = glide
            .asFile()
            .load(url)
            .addListener(object : RequestListener<File> {
                override fun onLoadFailed(
                    e: GlideException?,
                    model: Any?,
                    target: Target<File>?,
                    isFirstResource: Boolean
                ): Boolean {
                    it.resume(AwaitResult<File>(null, e))
                    return true
                }

                override fun onResourceReady(
                    resource: File?,
                    model: Any?,
                    target: Target<File>?,
                    dataSource: DataSource?,
                    isFirstResource: Boolean
                ): Boolean {
                    it.resume(AwaitResult(resource, null))
                    return true
                }
            })
            .submit()
        it.invokeOnCancellation { t ->
            request.cancel(true)
            it.resume(AwaitResult<File>(null, t))
        }
    }
}

suspend fun Context.downloadBitmapByGlide(url: String?): AwaitResult<Bitmap> {
    return downloadBitmapByGlide(url, Glide.with(this))
}

suspend fun Fragment.downloadBitmapByGlide(url: String?): AwaitResult<Bitmap> {
    return downloadBitmapByGlide(url, Glide.with(this))
}

suspend fun downloadBitmapByGlide(url: String?, glide: RequestManager): AwaitResult<Bitmap> {
    url ?: return AwaitResult(null, IllegalStateException("url is null"))
    return awaitAny {
        //多次resume会报错
        var isResume = false
        val request = glide
            .asBitmap()
            .load(url)
            .addListener(object : RequestListener<Bitmap> {
                override fun onLoadFailed(
                    e: GlideException?,
                    model: Any?,
                    target: Target<Bitmap>?,
                    isFirstResource: Boolean
                ): Boolean {
                    if (!isResume) {
                        isResume = true
                        it.resume(AwaitResult<Bitmap>(null, e))
                    }
                    return true
                }

                override fun onResourceReady(
                    resource: Bitmap?,
                    model: Any?,
                    target: Target<Bitmap>?,
                    dataSource: DataSource?,
                    isFirstResource: Boolean
                ): Boolean {
                    if (!isResume) {
                        isResume = true
                        it.resume(AwaitResult(resource, null))
                    }
                    return true
                }
            })
            .submit()
        it.invokeOnCancellation { t ->
            request.cancel(true)
            if (!isResume) {
                isResume = true
                it.resume(AwaitResult<Bitmap>(null, t))
            }
        }
    }
}

suspend fun Context.downloadDrawableByGlide(
    url: String?,
    width: Int,
    height: Int,
    isCircle: Boolean
): AwaitResult<Drawable> {
    url ?: return AwaitResult(null, IllegalStateException("url is null"))
    return awaitAny {
        val request = Glide.with(this)
            .asDrawable()
            .load(url)
            .also {
                if (isCircle) {
                    it.circleCrop()
                }
            }
            .addListener(object : RequestListener<Drawable> {
                override fun onLoadFailed(
                    e: GlideException?,
                    model: Any?,
                    target: Target<Drawable>?,
                    isFirstResource: Boolean
                ): Boolean {
                    it.resume(AwaitResult<Drawable>(null, e))
                    return true
                }

                override fun onResourceReady(
                    resource: Drawable?,
                    model: Any?,
                    target: Target<Drawable>?,
                    dataSource: DataSource?,
                    isFirstResource: Boolean
                ): Boolean {
                    it.resume(AwaitResult(resource, null))
                    return true
                }
            })
            .submit(width, height)
        it.invokeOnCancellation { t ->
            request.cancel(true)
            it.resume(AwaitResult<Drawable>(null, t))
        }
    }
}
/**
 * 设置视频预览画面
 * 必须要先缓存下来
 */
//fun ImageView.setVideoFrameGlide(url: String?, time: Long) {
//    url ?: return
//    Glide.with(context.applicationContext)
//        .setDefaultRequestOptions(
//            RequestOptions()
//                //这里限制了只从缓存读取
//                .onlyRetrieveFromCache(true)
//                .frame(1000 * time)
//                .override(413, 275)
//                .dontAnimate()
//                .placeholder(drawable)
//                .centerCrop()
//        )
//        .load(url)
//        .into(this)
//}

/**
 * 获取默认的加载选项
 */
fun getDefaultOption(radius: Int): RequestOptions {
    return when {
        radius < 0 -> {
            RequestOptions.bitmapTransform(CircleCrop())
        }
        radius == 0 -> {
            RequestOptions()
        }
        else -> {
            RequestOptions.bitmapTransform(RoundedCorners(radius))
        }
    }
}

/**
 * 通过Glide设置图片
 * 用自己的本身的可能导致内存泄漏
 * radius圆角半径，0 位方形，小于0 是圆 ，大于0 就是圆角的度数
 */
const val GLIDE_LOAD_RADIUS_NORMAL = 0
const val GLIDE_LOAD_RADIUS_CIRCLE = -1
fun GLIDE_LOAD_RADIUS_RADIUS(radius: Int) = dip(radius)

/**
 * "使用[setImageAny]替代"
 */
@Deprecated("使用[setImageAny]替代", replaceWith = ReplaceWith("使用[setImageAny]替代"))
fun RequestManager.startLoad(
    view: ImageView,
    obj: Any?/*地址*/,
    replace: Any? = null/*如果地址为null，这个作为新的地址*/,
    placeholder: Any? = null/*占位符，图片未加载出来的时候显示*/,
    radius: Int = GLIDE_LOAD_RADIUS_NORMAL/*radius圆角半径，0 位方形，小于0 是圆 ，大于0 就是圆角的度数*/,
    requestOptions: RequestOptions? = null/*配置*/,
    transition: DrawableTransitionOptions? = null/*转换*/
) {
    if (obj == null && replace == null) {
        when (placeholder) {
            is Drawable -> {
                view.setImageDrawable(placeholder)
            }
            is Int -> {
                view.setImageResource(placeholder)
            }
            else -> {
                view.setImageDrawable(null)
            }
        }
        this.clear(view)
    } else {
        this.load(obj ?: replace).apply {
            when (placeholder) {
                is Drawable -> {
                    placeholder(placeholder)
                }
                is Int -> {
                    placeholder(placeholder)
                }
                else -> {
                    placeholder(null)
                }
            }
            apply(requestOptions ?: getDefaultOption(radius))
            if (replace is Int) {
                error(replace)
            }
            if (transition != null) {
                transition(transition)
            } else {
                dontAnimate()
            }
            into(view)
        }
    }
}

/**
 * "使用[setImageAny]替代"
 */
@Deprecated("使用[setImageAny]替代", replaceWith = ReplaceWith("使用[setImageAny]替代"))
fun ImageView?.setImageGlide(
    obj: Any?/*需要显示的对象*/,
    replace: Any? = null/*如果目标为null，则显示这个*/,
    placeholder: Any? = null/*占位符，图片未加载出来的时候显示*/,
    radius: Int = GLIDE_LOAD_RADIUS_NORMAL/*设置图片圆角，像素是px*/,
    requestOptions: RequestOptions? = null/*设置自己的加载选项*/,
    transition: DrawableTransitionOptions? = null
) {
    this ?: return
    Glide.with(this).startLoad(this, obj, replace, placeholder, radius, requestOptions, transition)
}

/**
 * "使用[setImageAny]替代"
 */
@Deprecated("使用[setImageAny]替代", replaceWith = ReplaceWith("使用[setImageAny]替代"))
fun Fragment?.setImageGlide(
    view: ImageView/*图像载体*/,
    obj: Any?/*需要显示的对象*/,
    replace: Any? = null/*如果目标为null，则显示这个*/,
    placeholder: Any? = null/*占位符，图片未加载出来的时候显示*/,
    radius: Int = GLIDE_LOAD_RADIUS_NORMAL/*设置图片圆角，像素是px*/,
    requestOptions: RequestOptions? = null/*设置自己的加载选项*/,
    transition: DrawableTransitionOptions? = null
) {
    this ?: return
    Glide.with(this).startLoad(view, obj, replace, placeholder, radius, requestOptions, transition)
}

/**
 * "使用[setImageAny]替代"
 */
@Deprecated("使用[setImageAny]替代", replaceWith = ReplaceWith("使用[setImageAny]替代"))
fun AppCompatActivity?.setImageGlide(
    view: ImageView/*图像载体*/,
    obj: Any?/*需要显示的对象*/,
    replace: Any? = null/*如果目标为null，则显示这个*/,
    placeholder: Any? = null/*占位符，图片未加载出来的时候显示*/,
    radius: Int = GLIDE_LOAD_RADIUS_NORMAL/*设置图片圆角，像素是px*/,
    requestOptions: RequestOptions? = null/*设置自己的加载选项*/,
    transition: DrawableTransitionOptions? = null
) {
    this ?: return
    Glide.with(this).startLoad(view, obj, replace, placeholder, radius, requestOptions, transition)
}

/**
 * "使用[setImageAny]替代"
 */
@Deprecated("使用[setImageAny]替代", replaceWith = ReplaceWith("使用[setImageAny]替代"))
fun Context?.setImageGlide(
    view: ImageView/*图像载体*/,
    obj: Any?/*需要显示的对象*/,
    replace: Any? = null/*如果目标为null，则显示这个*/,
    placeholder: Any? = null/*占位符，图片未加载出来的时候显示*/,
    radius: Int = GLIDE_LOAD_RADIUS_NORMAL/*设置图片圆角，像素是px*/,
    requestOptions: RequestOptions? = null/*设置自己的加载选项*/,
    transition: DrawableTransitionOptions? = null
) {
    this ?: return
    Glide.with(this).startLoad(view, obj, replace, placeholder, radius, requestOptions, transition)
}

// Palette.Swatch s = palette.getDominantSwatch();       //独特的一种
// Palette.Swatch s1 = palette.getVibrantSwatch();       //获取到充满活力的这种色调
// Palette.Swatch s2 = palette.getDarkVibrantSwatch();    //获取充满活力的黑
// Palette.Swatch s3 = palette.getLightVibrantSwatch();   //获取充满活力的亮
// Palette.Swatch s4 = palette.getMutedSwatch();          //获取柔和的色调
// Palette.Swatch s5 = palette.getDarkMutedSwatch();      //获取柔和的黑
// Palette.Swatch s6 = palette.getLightMutedSwatch();     //获取柔和的亮
suspend fun Bitmap?.getPaletteSwatch(target: androidx.palette.graphics.Target = androidx.palette.graphics.Target.MUTED): Palette.Swatch? {
    this ?: return null
    return awaitAny {
        try {
            Palette.from(this).generate { generate ->
                it.resume(
                    generate?.get(target) ?: generate?.get(androidx.palette.graphics.Target.VIBRANT)
                )
            }
        } catch (e: Throwable) {
            printStackTrace { e }
            it.resume(null)
        }
    }
}

suspend fun Bitmap?.getPalette(): Palette? {
    this ?: return null
    return awaitAny {
        try {
            Palette.from(this).generate { generate ->
                it.resume(generate)
            }
        } catch (e: Throwable) {
            printStackTrace { e }
            it.resume(null)
        }
    }
}

suspend fun Bitmap?.getDominantSwatch(): Palette.Swatch? {
    this ?: return null
    return awaitAny {
        try {
            Palette.from(this).generate { generate ->
                it.resume(generate?.dominantSwatch)
            }
        } catch (e: Throwable) {
            printStackTrace { e }
            it.resume(null)
        }
    }
}

suspend fun Bitmap?.getDominantColor(defaultColor: Int): Int {
    this ?: return defaultColor
    return awaitAny {
        try {
            Palette.from(this).generate { generate ->
                it.resume(generate?.getDominantColor(defaultColor) ?: defaultColor)
            }
        } catch (e: Throwable) {
            printStackTrace { e }
            it.resume(defaultColor)
        }
    }
}

suspend fun Activity?.getPaletteSwatch(
    url: String?,
    target: androidx.palette.graphics.Target
    = androidx.palette.graphics.Target.MUTED
): Palette.Swatch? {
    return this?.downloadBitmapByGlide(url)?.result.getPaletteSwatch(target)
}

suspend fun Fragment?.getPaletteSwatch(
    url: String?,
    target: androidx.palette.graphics.Target
    = androidx.palette.graphics.Target.MUTED
): Palette.Swatch? {
    return this?.downloadBitmapByGlide(url)?.result.getPaletteSwatch(target)
}

suspend fun Activity?.getDominantSwatch(url: String?): Palette.Swatch? {
    return this?.downloadBitmapByGlide(url)?.result.getDominantSwatch()
}

suspend fun Fragment?.getDominantSwatch(url: String?): Palette.Swatch? {
    return this?.downloadBitmapByGlide(url)?.result.getDominantSwatch()
}

suspend fun Activity?.getDominantColor(url: String?, defaultColor: Int): Int {
    return this?.downloadBitmapByGlide(url)?.result.getDominantColor(defaultColor)
}

suspend fun Fragment?.getDominantColor(url: String?, defaultColor: Int): Int {
    return this?.downloadBitmapByGlide(url)?.result.getDominantColor(defaultColor)
}

/**
 * 利用鲁班压缩
 */
@WorkerThread
fun Context.compressByLuban(urls: List<String>): List<File> {
    return Luban.with(this).load(urls).get()
}

/**
 * 利用鲁班压缩
 */
fun Context.compressByLuban(url: String): File {
    return Luban.with(this).load(url).get().first()
}


/**
 * 利用鲁班压缩
 */
@WorkerThread
fun Context.compressFileByLuban(files: List<File>): List<File> {
    return Luban.with(this).load(files).get()
}

/**
 * 利用鲁班压缩
 * maxSize：>0 如果图片大于这个值，则会一直压缩到小于等于这个值
 *          如果图片小于这个值，则不进行压缩
 *          <=0 不论图片大小如何，都进行一次压缩
 *
 */
@WorkerThread
fun Context.compressFileByLuban(file: File, maxSize: Long = -1): File {
    return if (maxSize > 0) {
        val fileSize = file.length()
        if (fileSize > maxSize) {
            val compressFile = Luban.with(this).load(file).get().first()
            //递归压缩。知道满足压缩要求
            compressFileByLuban(compressFile, maxSize)
        } else {
            file
        }
    } else {
        Luban.with(this).load(file).get().first()
    }
}
